#!/usr/bin/python
# Filename: mjc_server.py

import threading
import logging
import socket
import sys
import os
import json
from mjs_public import singleton
from mjs_conf import mjs_conf
import mjc_client

mjs_conf_mgr = mjs_conf.MjsConf()

user_root_dir = '/etc/mangjingw/user/'

class MjcServer(singleton.Singleton, threading.Thread):

    client_dict = {}
    client_user_ip_dict = {}
    client_ip_user_dict = {}

    def __init__(self, mjw_server):
        self.mjw_server = mjw_server
        self.mjw_server.set_mjc_server(self)
        super(MjcServer, self).__init__()

    def __del__(self):
        self.serversocket.close()

    def regist(self, user_name, ip):
        client_ip_list = self.client_user_ip_dict.get(user_name)
        if client_ip_list == None:
            ip_list = [ip]
            self.client_user_ip_dict[user_name] = ip_list
        else:
            if ip not in client_ip_list:
                client_ip_list.append(ip)

        user = self.client_ip_user_dict.get(ip)
        if not user:
            self.client_ip_user_dict[ip] = user_name

    def unregist(self, user_name, ip):
        client_ip_list = self.client_user_ip_dict.get(user_name)
        if client_ip_list == None:
            logging.error("don't found user:%s ip:%s in client_user_ip_dict" % (user_name, ip))
            return False
        else:
            client_ip_list.remove(ip)
            logging.info("user:%s ip:%s remove from client_ip_list" % (user_name, ip))

    def find_user_by_ip(self, ip):
        return self.client_ip_user_dict.get(ip)

    def handle_mjw_req(self, action_req):
        user_name = action_req['user_name']
        client_ip_list = self.client_user_ip_dict.get(user_name)
        if client_ip_list == None:
            logging.error("user '%s' have not client connected to mangjings , can't execute action" % user_name)
            self.__response_sys_error(user_name, "user '%s' server offline" % user_name)
            return False

        action = action_req['action']
        if action == 'user_config_changed':
            file_name = action_req['file_name']
            user_dir = user_root_dir + user_name + '/'
            for con_ip in client_ip_list:
                client_config_file = user_dir + con_ip + '/config/' + file_name
                if os.path.exists(client_config_file):
                    continue

                client_obj = self.client_dict.get(con_ip)
                if client_obj == None:
                    logging.error("client %s don't connected mangjings" % req_ip)
                    continue

                client_obj.handle_mjw_req(action_req)
        else:
            req_ip_list = action_req['ips']
            if len(req_ip_list) == 0:
                logging.error("request node 'ip_list' is empty")
                self.__response_sys_error(user_name, "user '%s' server offline" % user_name)
                return False

            for req_ip in req_ip_list:
                found_client = False
                for con_ip in client_ip_list:
                    if req_ip == con_ip:
                        found_client = True
                        break

                if not found_client:
                    logging.error("user:%s client:%s don't connect to mangjings" % (user_name, req_ip))
                    self.__response_sys_error(user_name, "user '%s' server offline" % user_name)
                    break

                client_obj = self.client_dict.get(req_ip)
                if client_obj == None:
                    logging.error("client %s don't connected mangjings" % req_ip)
                    continue

                client_obj.handle_mjw_req(action_req)

    def run(self):
        logging.info("thread accept_thread startup")
        while True:
            clientsocket, addr = self.serversocket.accept()
            ip = str(addr[0])
            logging.info("accept client:%s conneting"%(ip))

            if self.client_dict.get(ip) != None:
                logging.info("delete had connect : %s"%(self.client_dict[ip].ip))
                del self.client_dict[ip]

            client = mjc_client.MjcClient(clientsocket, ip, self, self.mjw_server)
            self.client_dict[ip] = client

    def startup(self):
        self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        host = mjs_conf_mgr.host

        try:
            self.serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.serversocket.bind((host, mjs_conf_mgr.mjc_port))
            self.serversocket.listen(mjs_conf_mgr.mjc_max)
            logging.info("mjc_server addr:%s:%d" % (socket.gethostbyname(host), mjs_conf_mgr.mjc_port))
        except Exception, e:
            logging.error("start mjc server failed: %s" % e)
            return False

        self.start()

        return True

    def __response_sys_error(self, user_name, error):
        res_dict = {
            "action": "sys_error",
            "user_name": user_name,
            "error_code": "002",
            "error": error
        }

        res_json = json.dumps(res_dict, indent=1)
        self.mjw_server.send(res_json)

    pass